/*  
  -- The Lime II Project -- 

  A tuplespaces-based middleware for coordinating agents and mobile hosts.
  Copyright (C) 2005.
  Gian Pietro Picco, Amy L. Murphy, Lorenzo Bellini.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received this copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/

package lime2;
import java.util.*;

/**
 * Provides facilities for the reuse of threads. Allows to resize the number of threads on the fly; supports resizable
 * thread related data structures. A thread related data structure is usually a Hashtable (Vector, array, etc..) that
 * contains a specific entry for each thread of the pool. The advantage of thread related data structures is that they
 * are reused by "tasks". 
 * Please note that support for thread related data structures must be provided by the thread pool itself (and not by
 * an external class) only if we want the data structures to be resizable.
 * <br>
 * <br>
 * <i>Special thanks to Paul Klapwijk for helping to debug this class.</i>
 *  
 * @author Gian Pietro Picco
 * @author Amy Murphy
 * @author Lorenzo Bellini
 */

public class ThreadPool extends ThreadGroup
{
 // private data members	
 private int n;            // number of workers managed by this pool
 private int active;       // number of workers that are busy now (<= n)
 private int active_max;   // maximum number of workers that were busy at the same moment (active <= active_max <= n) 
 private Worker[] workers; // workers 
 private LinkedList todo;  // tasks still to assign 
 
 /**
  * Creates a thread pool managing <code>m</code> threads. The name of its thread is the corresponding number
  * (from <code>0</code> to <code>m - 1</code>); this provides unique identification. 
  * 
  * @param m number of threads this pool must manages
  */
 public ThreadPool(int m)
 { 	
  // super	
  super("pool");	
  // initializations
  n = m;	
  active = 0;
  active_max = 0;
  workers = new Worker[n];
  todo = new LinkedList();
  setUp(m);
  // starts the workers
  for (int i = 0; i < n; i++) 
  { 
   workers[i] = new Worker(this, String.valueOf(i));
   workers[i].start(); 
  }
 }
 
 /**
  * Changes the number of threads this pool manages.
  * <br>
  * Let us call <code>n</code> the current number of managed threads, and <code>m</code> the new number.
  * <br>
  * If <code>m</code> is greater than <code>n</code>, additional threads are simply started.
  * <br>
  * If <code>m</code> is less than <code>n</code>, then <code>m</code> - <code>n</code> threads will die <i>after</i>
  * completing the tasks that were assigned to them (<i>safe death</i>). 
  * <br>
  * If <code>m</code> is equal to <code>n</code>, nothing happens.
  * <br>
  * This method is synchronized since we cannot allow two or more concurrent resize to be in progress.
  * 
  * @param m the new number of threads this pool will manage
  */
 synchronized public void resize(int m)
 {	
  if (m > n) 
  {
   resizeUp(m);	
   Worker[] ws = new Worker[m];  	
   for (int i = 0; i < n; i++) ws[i] = workers[i];
   for (int i = n; i < m; i++) 
   { 
    ws[i] = new Worker(this, String.valueOf(i));
    ws[i].start();
   }
   workers = ws;
   n = m;
  }
  else if (m < n)
  {
   // "resizeDown" is achieved by "cleanUp": the thread related data structures (if any) must be updated only when we 
   // are sure that the dying thread has finished using them  	
   for (int i = 0; i < n - m; i++) workers[n - 1 - i].safeDie(); 	
   notifyAll();
   Worker[] ws = new Worker[m];
   for (int i = 0; i < m; i++) ws[i] = workers[i];
   workers = ws;
   n = m;
  }
 }
 
 /**
  * Returns the number of threads this pool manages.
  *  
  * @return the number of threads this pool manages
  */
 public int poolSize()
 {
  return n;	
 }
 
 /**
  * Returns the number of threads that are busy (= executing a task, NOT waiting) now.
  *  
  * @return the number of threads that are busy now
  */
 public int busyNow()
 {
  return active;	
 }
 
 /**
  * Returns the number of enqueued tasks that did not begin to be executed yet. This method is synchronized in order 
  * to protect the internal representation of the tasks.
  * <br>
  * <br>
  * <i>Implementative Detail</i>
  * <br>
  * <code>java.util.LinkedList</code> is not synchronized, <code>java.util.Vector</code> is synchronized: we chose 
  * LinkedList and not Vector because we wanted to provide our own synchronization. 
  * <br>
  * The methods "assignTask" and "consumeTask" must be synchronized since they manipulate the LinkedList: please note
  * that they are very fast methods. The method "toDo" could be not synchronized since it doesn't change the structure
  * of the LinkedList (see <code>java.util.LinkedList</code>).  
  * 
  * @return the number of enqueued tasks that did not begin to be executed yet
  */
 synchronized public int toDo()
 {
  return todo.size();
 }
 
 /**
  * Returns the maximum number of threads that were busy at the same moment. The time-span goes from the creation
  * of the thread pool until now. This method can be useful to find out which is the correct number of threads the
  * pool should manage. 
  * <br>
  * ThreadPool could be extended so that it automatically performs load balancing:
  * <br><br>
  * <code>
  * :each X time
  * <br>
  * if (busyMax() == poolSize()) resize(poolSize() + workingSetFactor) 
  * <br>
  * else resize(busyMax())
  * </code>
  * 
  * @return the maximum number of threads that were busy at the same moment, from the creation of the pool til now
  */
 public int busyMax() 
 {
  return active_max;	
 }
 
 /**
  * The given task (described by the "run" method of a Runnable object) will be executed by the first non-busy thread.
  * If none of the threads is "waiting", then the task will be executed as soon as one one of the threads is idle. 
  * It is guaranteed that tasks are picked-up by threads in a FIFO order (first job in, first job that will start). 
  * This method is synchronized in order to protect the internal representation of the tasks. 
  * 
  * @param task to execute
  */
 synchronized public void assignTask(Runnable task)
 {
  todo.addLast(task);
  notify();
 }
 
 /**
  * Returns a task to an instance of Worker. If there are not tasks available at this instant, it returns <code>null
  * </code>. This method is synchronized in order to protect the internal representation of the tasks.
  * 
  * @return task, if there is (at least) one available; othewise <code>null</code> is returned
  */
 synchronized Runnable consumeTask()
 {
  if (todo.size() == 0) return null; else return (Runnable) todo.removeFirst(); 
 }
 
 /**
  * Makes a thread to wait for an available task.
  */
 synchronized void waitTask() throws InterruptedException
 {
  if (todo.size() == 0) wait();	
 }
 
 /**
  * Initializes thread related data structures (if any): this method is invoked by the constructor of the thread pool
  * before starting the threads (no need of synchronization). 
  *
  * @param m number of threads the pool has to manage
  */
 void setUp(int m)
 {
  // customize	
 }
 
 /** 
  * Changes thread related data structures (if any) that may require to be updated because of an "increasing" resize 
  * of the thread pool. This method doesn't need to be synchronized since it is invoked within method "resize" which 
  * is synchronized.
  *
  * @param m the new number of threads this pool will manage
  */
 void resizeUp(int m)
 {
  // customize	
 }
 
 /**
  * Performs clean up of thread related data structures (if any) that may require to be updated because of the death 
  * of a thread (.. "decreasing" resize of the thread pool). This method is synchronized since multiple threads can 
  * die at the "same time" (causing a bad interleaving).
  * 
  * @param thread name of the dead thread
  */
 synchronized void cleanUp(String thread) 
 {
  // customize	
 }
 
 /**
  * When the main thread in a single-threaded application throws an uncaught exception, you are likely to notice 
  * because the stack trace is printed on the console (and because the program stops). But in a multithreaded 
  * application, especially one that runs as a server and is not attached to a console, thread death may be a less 
  * noticeable event, resulting in partial system failures that can cause confusing application behavior. 
  * <br>
  * This method is called by the Java Virtual Machine when a thread in this thread group stops because of an uncaught
  * exception. 
  * <br>
  * We just override this method of ThreadGroup so that the Lime console informs us about threads that disappear 
  * because of unhandled exceptions. But please note that the method "run" of Worker handles any exception: so 
  * "uncaughtException" should come into play only for abnormal situations in which interruption of threads causes
  * thread leakage.
  * 
  * @param t Thread
  * @param e Exception
  */
 public void uncaughtException(Thread t, Throwable e)
 {
  e.printStackTrace();	
 }
 
 /**
  * Inner class. Models a "worker" thread.
  *  
  * @author Gian Pietro Picco
  * @author Amy Murphy
  * @author Lorenzo Bellini
  */
 class Worker extends Thread
 {
  // private data member: should we keep this thread alive ? 	
  private boolean alive;

  /**
   * Constructor method.
   *
   * @param ts thread group this worker belongs to
   * @param name name of this worker
   */
  Worker(ThreadGroup ts, String name)
  {	
   super(ts, name);	
   alive = true;
  }

  /**
   * Enables "safe death" of a thread, that is to say that the thread will die only after it completes the task it 
   * was assigned, if any.
   */ 
  void safeDie()
  {
   alive = false;
  }
  
  /**
   * Run method.
   * <br>
   * Please note that a worker:
   * <P>
   * &#9679 waits for a task to be assigned to the ThreadPool, grabs it (competing with the other workers for 
   * precedence), executes it and goes back to the "waiting state" 
   * <br>
   * &#9679 calls the "run" method of the task (doesn't "start" the task)
   * <br>
   * &#9679 can die "safely" (see method "safeDeath") 
   * <br>
   * &#9679 at the very last moment before it dies, it calls the "cleanUp" method to preserve consistency of thread 
   * related data structures (if any) that may require to be updated because of its death
   * <br>
   * &#9679 catches all the Exceptions in order to prevent thread leakage (if an Exception is thrown and the thread 
   * doesn't handle it the thread halts, disappearing from the pool - see comment of method 
   * "ThreadPool.uncaughtException" about this). This means that a thread can be killed only because of a resize of 
   * the pool, not because of an Exception 
   * </P>
   */
  public void run()
  {
   while (alive) 
   {
    try  
    { 
     waitTask();
     if (alive) 
     {	
      Runnable task = consumeTask(); 
      if (task != null) 
      { 
       active++; 
       if (active > active_max) active_max = active; 
       task.run(); 
       active--; 
      }
     }
    } 
    catch (ProtocolTerminationException pte) { }
    catch (Exception e) { e.printStackTrace(); }   	
   }
   cleanUp(Thread.currentThread().getName());
  }
  
 } // end class Worker
 
} // end class ThreadPool

